﻿using System;
using StackExchange.Redis;
using WeDonekRpc.Helper;

namespace WeDonekRpc.CacheClient.Redis
{
    public class SyncBasicRedisQS<T> : IDisposable
    {
        private readonly RedisClient _Client;
        private readonly string _QueueName = null;

        public string QueueName => this._QueueName;

        public bool IsConnected => this._Client.IsConnected;
        private readonly bool _IsMuilt = true;
        public SyncBasicRedisQS (string name, bool isFull = false)
        {
            this._Client = RedisHelper.GetNewClient(name);
            IServer[] servers = this._Client.GetServers();
            if (servers.IsExists(c => c.Version.Major == 5))
            {
                this._IsMuilt = false;
            }
            this._QueueName = isFull ? ( this._QueueName = string.Join("_", name, Environment.MachineName) ) : RpcCacheService.FormatKey(name);
        }

        protected IDatabase DataBase => this._Client.DataBase;
        public long GetCount ()
        {
            return SyncRedisHelper.GetListCount(this._Client.DataBase, this._QueueName);
        }
        public bool CopyTo (T[] array, int index)
        {
            if (SyncRedisHelper.GetList<T>(this._Client.DataBase, this.QueueName, out T[] data) && data != null)
            {
                data.CopyTo(array, index);
                return true;
            }
            return false;
        }
        public bool TryDequeue (out T data)
        {
            return SyncRedisHelper.ListLeftPop<T>(this._Client.DataBase, this._QueueName, out data);
        }
        public bool TryDequeue (int count, out T[] data)
        {
            if (this._IsMuilt)
            {
                return SyncRedisHelper.ListLeftPop<T>(this._Client.DataBase, this._QueueName, count, out data);
            }
            Span<T> span = new Span<T>(new T[count]);
            for (int i = 0; i < count; i++)
            {
                if (SyncRedisHelper.ListLeftPop<T>(this._Client.DataBase, this._QueueName, out T one))
                {
                    span[i] = one;
                }
                else if (i == 0)
                {
                    data = null;
                    return false;
                }
                else
                {
                    data = span.Slice(0, i).ToArray();
                    return true;
                }
            }
            data = span.ToArray();
            return true;
        }

        public bool TryPeekRange (int index, int size, out T[] data)
        {
            return SyncRedisHelper.GetList<T>(this._Client.DataBase, this._QueueName, index, size, out data);
        }
        public bool TryPeek (out T data)
        {
            return SyncRedisHelper.GetList<T>(this._Client.DataBase, this._QueueName, 0, out data);
        }
        public bool TryPeek (out T[] data)
        {
            return SyncRedisHelper.GetList<T>(this._Client.DataBase, this.QueueName, out data);
        }
        public bool TryPeek (int index, out T data)
        {
            return SyncRedisHelper.GetList<T>(this._Client.DataBase, this.QueueName, index, out data);
        }

        public void Dispose ()
        {
            this._Client.Dispose();
        }
    }
}
